package system;

import java.util.ArrayList;

import common.Book;

import ui.MainMenuUI;
import ui.ResultsUI;



public class NmfAlg  {
	
	public int maxiter;
	public Matrix U;
	public Matrix V;
	public Matrix epsMatU;
	public Matrix epsMatV;
	public int m;
	public int n;
	public static int k;
	public double l; // current iteration
	public static ArrayList<Integer> clusterList;
	public static ArrayList<Integer> docsAtCluster;
	public static String log="";
	public static double progress;
	
	
	
	public  NmfAlg(int m,int n,int k,int max,double eps){
		
	
		 maxiter=max;
		
		 this.m=m;
		 this.n=n;
		 this.k=k;

		U=Matrix.random(m, k);
		V = Matrix.random(n, k);
		
		epsMatU = new Matrix(m, k, eps);
		epsMatV = new Matrix(n, k, eps);

	
	
	}


	public double[][] run(double[][] x){

		
		Matrix T, UT1, UT2,VT1,VT2,Uold,Vold,Udist,Vdist;
		
		Matrix X= new Matrix (x);
		
	
		int flagU,flagV;
		
		flagU=0;
		flagV=0;
		
		//stop conditions
		l=0;
		MainMenuUI.button_2.setEnabled(false);
		double temp=0;
		progress=0;
		MainMenuUI.progressBar.setValue(0);
	for(;l<maxiter&&flagU!=m*k&&flagV!=n*k;l++ )	{
		flagU=0;
		flagV=0;
		
	    if(MainMenuUI.alg==1){
	    	temp=0+(l/maxiter)*100;
	    	MainMenuUI.progressBar.setValue((int)temp);
	    	
	    	MainMenuUI.ChangeProgressBar();
	    	
	    	MainMenuUI.lblRunStatus.setText("NMF IN PROGRESS...");
	    }
	    else{
	    //Algorithm.temp=progress+ (l/maxiter)*(100.0/9);	
	    }
		
		
		// U
		
		Uold=U;
	
		T = V.transpose().times(V);

		UT1 = X.times(V);

		UT2 = U.times(T);
		
		UT2.plusEquals(epsMatU);

		UT1.arrayRightDivideEquals(UT2);
		
		U.arrayTimesEquals(UT1);
		
		Uold.uminus();
		
		Udist=U.plus(Uold);
		
		for(int i=0;i<m;i++){
			for(int j=0;j<k;j++){
				if(Math.abs(Udist. get(i,j))<=epsMatU.get(i,j))
					flagU++;
			}
		}
	
		// V
		
		Vold=V;
		
		T = U.transpose().times(U);

		VT1 = X.transpose().times(U);
		
		VT2 = V.times(T);
	
		VT2.plusEquals(epsMatV);
	
		VT1.arrayRightDivideEquals(VT2);
		
		V.arrayTimesEquals(VT1);
		
		Vold.uminus();
		
		Vdist=V.plus(Vold);
		
		
		for(int i=0;i<n;i++){
			for(int j=0;j<k;j++){
				if(Math.abs(Vdist. get(i,j))<=epsMatV.get(i,j))
					flagV++;
			}
		}
		
	}//for

if(MainMenuUI.X.alg==1){
	
	log=log+("NMF CLASIFICATION RESULTS: \n\n");
	log=log+("Number of iteration: "+l+"\n\n");
}
	
	//normalization
	double[] dist=new double[m];
	for(int i=0;i<m;i++){
		for(int j=0;j<k;j++){
			dist[i]= dist[i] + U.get(i, j)*U.get(i, j);
		}
	dist[i]=Math.sqrt(dist[i]);
	
	}
	
	//V norm
	double[][] Vnorm=new double[n][k];
	
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<k;j++){
			Vnorm[i][j]=V.get(i, j);
			Vnorm[i][j]=Vnorm[i][j]*dist[i];
		}
	}
	

	if(MainMenuUI.X.alg==1){
	log=log+("Clasification Matrix: \n\n");
	}
	
	if(MainMenuUI.X.alg==1){
	int book_index=0;
	clusterList=new ArrayList<Integer>();
	
	for(int i=0;i<k;i++)
	{
		clusterList.add(0);
	}
	
	boolean flag=true;

	for(int i=0;i<n;i++){
		if(flag){
		for(int j=0;j<k;j++){
			log=log+("Cluster "+j+"\t\t");
		}
		
		}
		
		flag=false;
		
		if(i%(n/(MainMenuUI.RunningBooks.size()))==0){
			log=log+("\n"+MainMenuUI.RunningBooks.get(book_index).getTitel()+"\n");
			book_index++;
		}
		double max=0;
		int max_index=0;
		for(int j=0;j<k;j++){
			
			double xtemp = Math.floor(Vnorm[i][j] * 10000);
			log=log+(i+" . "+xtemp+"\t\t ");
			if(xtemp>max)
			{
				max_index=j;
				max=xtemp;
			}
		}
		clusterList.set(max_index,clusterList.get(max_index)+1);
		
		log=log+("\n");
	}
	}
	
	if(MainMenuUI.alg==1){
		
	MainMenuUI.lblRunStatus.setText("NMF PROCCESS COMPLITED!");
	}
	else
		progress=progress+10.0;
	return Vnorm;
	
	     
}//run


}
